#include "rtda/heap/string_pool.h"
#include "rtda/heap/class.h"

namespace jvm {
    namespace heap {



        // Initialize the static instance
        StringPool StringPool::instance;

        StringPool& StringPool::getInstance() {
            return instance;
        }

        // utf8 -> utf16
        std::vector<uint16_t> StringPool::stringToUtf16(const std::string& s) {
            // Note: This is a simplified version. Proper UTF-8 to UTF-16 conversion
            // would require more complex handling of surrogate pairs and validation.
            std::vector<uint16_t> utf16;
            for (size_t i = 0; i < s.size(); ) {
                if ((s[i] & 0x80) == 0) { // 1-byte UTF-8
                    utf16.push_back(static_cast<uint16_t>(s[i]));
                    i += 1;
                }
                else if ((s[i] & 0xE0) == 0xC0) { // 2-byte UTF-8
                    if (i + 1 >= s.size()) break;
                    uint16_t code = ((s[i] & 0x1F) << 6) | (s[i + 1] & 0x3F);
                    utf16.push_back(code);
                    i += 2;
                }
                else if ((s[i] & 0xF0) == 0xE0) { // 3-byte UTF-8
                    if (i + 2 >= s.size()) break;
                    uint16_t code = ((s[i] & 0x0F) << 12) | ((s[i + 1] & 0x3F) << 6) | (s[i + 2] & 0x3F);
                    utf16.push_back(code);
                    i += 3;
                }
                else { // 4-byte UTF-8 (would need surrogate pairs)
                    // Simplified handling - just skip for now
                    i += 4;
                }
            }
            return utf16;
        }

        // utf16 -> utf8
        std::string StringPool::utf16ToString(const std::vector<uint16_t>& s) {
            std::string utf8;
            for (uint16_t code : s) {
                if (code <= 0x7F) { // 1-byte UTF-8
                    utf8.push_back(static_cast<char>(code));
                }
                else if (code <= 0x7FF) { // 2-byte UTF-8
                    utf8.push_back(static_cast<char>(0xC0 | (code >> 6)));
                    utf8.push_back(static_cast<char>(0x80 | (code & 0x3F)));
                }
                else { // 3-byte UTF-8
                    utf8.push_back(static_cast<char>(0xE0 | (code >> 12)));
                    utf8.push_back(static_cast<char>(0x80 | ((code >> 6) & 0x3F)));
                    utf8.push_back(static_cast<char>(0x80 | (code & 0x3F)));
                }
            }
            return utf8;
        }


        // cpp std::string(utf8) -> java.lang.String
        ObjectPtr StringPool::JString(std::shared_ptr<ClassLoader> loader, const std::string& cStr) {
            auto it = internedStrings.find(cStr);
            if (it != internedStrings.end()) {
                return it->second;
            }

            std::vector<uint16_t> chars = stringToUtf16(cStr);
            //auto jChars = std::make_shared<Object>(loader->loadClass("[C"), chars);
            //auto jChars = GC::g_s_gc.allocate<Object>(loader->loadClass("[C"), std::any(chars));
            auto jChars = heap::GC::g_s_gc.allocate<Object>(loader->loadClass("[C"), std::any(chars));

            auto jStr = loader->loadClass("java/lang/String")->newObject();
            jStr->setRefVar("value", "[C", jChars);

            internedStrings[cStr] = jStr;
            return jStr;
        }

        // java.lang.String -> CPP std::string(utf8)
        std::string StringPool::CPPString(ObjectPtr jStr) {
            auto charArr = jStr->getRefVar("value", "[C");
            return utf16ToString(charArr->chars());
        }

        ObjectPtr StringPool::internString(ObjectPtr jStr)
        {
            auto&& cppStr = CPPString(jStr);
            auto it = internedStrings.find(cppStr);
            if (it != internedStrings.end()) {
                return it->second;
            }

            internedStrings[cppStr] = jStr;
            return jStr;
        }


    } // namespace heap
}// namespace jvm